﻿using System;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine;
using SharpDepend.Storage;
using System.IO;
using SharpDepend.Storage.DataFormats;
using DefaultDspPlugins.UI.Common.Modulizer.Engine.GUIv2.FrontEndComponents;

namespace DefaultDspPlugins.UI.Common.Modulizer.Engine.GUI
{
    public class ModuleUIAttribute : Attribute
    {
        public Type ModuleType { get; private set; }

        public ModuleUIAttribute(Type moduleType)
        {
            ModuleType = moduleType;
        }
    }

    public sealed class BackgroundAlgorithmExpression
    {
        /// <summary>
        /// For color R.
        /// Mathematic algorithm to render background. The excpetion will be calculated for every pixels.
        /// 
        /// Built in variables:
        /// <para>
        /// X: X pixel.
        /// </para>
        /// <para>
        /// Y: Y pixel.
        /// </para>
        /// </summary>
        public string R { get; set; }

        /// <summary>
        /// For color G.
        /// Mathematic algorithm to render background. The excpetion will be calculated for every pixels.
        /// 
        /// Built in variables:
        /// <para>
        /// X: X pixel.
        /// </para>
        /// <para>
        /// Y: Y pixel.
        /// </para>
        /// </summary>
        public string G { get; set; }

        /// <summary>
        /// For color B.
        /// Mathematic algorithm to render background. The excpetion will be calculated for every pixels.
        /// 
        /// Built in variables:
        /// <para>
        /// X: X pixel.
        /// </para>
        /// <para>
        /// Y: Y pixel.
        /// </para>
        /// </summary>
        public string B { get; set; }
    }

    public abstract class BaseModuleUI
    {
        private int mRow;
        private int mRowSpan;
        private int mColumn;
        private int mColumnSpan;

        public BaseModule Module { get; private set; }

        internal CustomNode SerializedLayout { get; set; }

        public event Action LayoutChanged;
        
        public BaseModuleUI(BaseModule module)
        {
            if (module == null)
            {
                throw new ArgumentNullException(nameof(module));
            }
            Module = module;
            
            Background.R = string.Empty;
            Background.G = string.Empty;
            Background.B = string.Empty;

            Row = 0;
            RowSpan = 1;
            Column = 0;
            ColumnSpan = 1;

            SetLayout(module);
        }

        internal void DoLayout()
        {
            SetLayout(Module);
        }

        private void SetLayout(BaseModule module)
        {
            string layout = OnSetLayout(module);

            using (MemoryStream ms = new MemoryStream())
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(layout);
                ms.Write(data, 0, data.Length);
                CustomNode node = new CustomNode();
                node.SetData(new SimpleC(), ms);

                SerializedLayout = node;
            }
        }

        protected abstract string OnSetLayout(BaseModule module);

        internal void RaiseOnUICreated(ModuleUIPanel uiPanel)
        {
            OnUICreated(uiPanel);
        }

        public virtual void Refresh()
        {
        }

        protected abstract void OnUICreated(ModuleUIPanel uiPanel);

        internal void RaiseOnUIDestroyed(ModuleUIPanel uiPanel)
        {
            OnUIDestoyed(uiPanel);
        }

        protected abstract void OnUIDestoyed(ModuleUIPanel uiPanel);

        public int Row
        {
            get { return mRow; }
            set
            {
                if (value < 0)
                {
                    throw new IndexOutOfRangeException("Row can not be lesser than 0");
                }
                mRow = value;
                LayoutChanged?.Invoke();
            }
        }

        public int RowSpan
        {
            get { return mRowSpan; }
            set
            {
                if (value <= 0)
                {
                    throw new IndexOutOfRangeException("RowSpan can not be 0 or less");
                }
                mRowSpan = value;
                LayoutChanged?.Invoke();
            }
        }

        public int Column
        {
            get { return mColumn; }
            set
            {
                if (value < 0)
                {
                    throw new IndexOutOfRangeException("Column can not be lesser than 0");
                }
                mColumn = value;
                LayoutChanged?.Invoke();
            }
        }

        public int ColumnSpan
        {
            get { return mColumnSpan; }
            set
            {
                if (value <= 0)
                {
                    throw new IndexOutOfRangeException("ColumnSpan can not be 0 or less");
                }
                mColumnSpan = value;
                LayoutChanged?.Invoke();
            }
        }

        //internal void SetModule(BaseModule module)
        //{
        //    if (module == null)
        //    {
        //        throw new ArgumentNullException(nameof(module));
        //    }
        //    Module = module;
        //}

        public BackgroundAlgorithmExpression Background { get; set; } = new BackgroundAlgorithmExpression();
    }
}
